/**
 * 
 */
package org.starsource.forum.server.dao.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.LinkedHashSet;
import java.util.NoSuchElementException;
import java.util.Set;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;

import org.starsource.forum.client.exception.DatabaseException;
import org.starsource.forum.client.exception.LoginFailNotFoundException;
import org.starsource.forum.server.dao.LoginFailDao;
import org.starsource.forum.server.domain.LoginFail;

/**
 * @author james
 *
 */
public class LoginFailDaoJdbc implements LoginFailDao {

	private JdbcTemplate jdbcTemplate;

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	private static org.apache.log4j.Logger logger = org.apache.log4j.LogManager
	.getLogger(LoginFailDaoJdbc.class.getName());

	private class GroupRowCallbackHandler implements RowCallbackHandler {
		private Set<LoginFail> loginFailSet;
		
		public void processRow(ResultSet rs) throws SQLException {
			LoginFail loginFail = new LoginFail();
			loginFail.setId(rs.getInt("id"));
			loginFail.setAccount(rs.getString("account"));
			loginFail.setIp(rs.getString("ip"));
			loginFail.setTimestamp(rs.getTimestamp("timestamp"));
			loginFailSet.add(loginFail);
		}
		
		public GroupRowCallbackHandler(Set<LoginFail> loginFailSet) {
			this.loginFailSet = loginFailSet;
		}
	}

	/* (non-Javadoc)
	 * @see org.starsource.forum.server.dao.LoginFailDao#delete(org.starsource.forum.server.domain.LoginFail)
	 */
	@Override
	public void delete(final LoginFail loginFail) throws DatabaseException {
		try {
			final String sql = "DELETE FROM t_login_fail WHERE id = ?";
			jdbcTemplate.update(new PreparedStatementCreator() {
				public PreparedStatement createPreparedStatement(Connection conn) throws SQLException {
					PreparedStatement ps = conn.prepareStatement(sql);
					ps.setInt(1, loginFail.getId());
					return ps;
				}
			});
		} catch (DataAccessException e) {
			logger.error(e.toString());
			throw new DatabaseException();
		}
	}

	/* (non-Javadoc)
	 * @see org.starsource.forum.server.dao.LoginFailDao#getLoginFail(int)
	 */
	@Override
	public LoginFail getLoginFail(int id) throws LoginFailNotFoundException,
			DatabaseException {
		try {
			String sql = "SELECT * FROM t_login_fail WHERE id = ? ";
			final Set<LoginFail> loginFailSet = new LinkedHashSet<LoginFail>();
			jdbcTemplate.query(sql, new Object[] {id}, new GroupRowCallbackHandler(loginFailSet));
			return loginFailSet.iterator().next();
		} catch (DataAccessException e) {
			logger.error(e.toString());
			throw new DatabaseException();
		} catch (NoSuchElementException e) {
			logger.error(e.toString());
			throw new LoginFailNotFoundException();
		}
	}

	/* (non-Javadoc)
	 * @see org.starsource.forum.server.dao.LoginFailDao#save(org.starsource.forum.server.domain.LoginFail)
	 */
	@Override
	public void save(final LoginFail loginFail) throws DatabaseException {
		final String sql = "INSERT INTO t_login_fail(account, ip, timestamp) VALUES(?,?,?)";
		KeyHolder keyHolder = new GeneratedKeyHolder();
		jdbcTemplate.update(new PreparedStatementCreator() {
			public PreparedStatement createPreparedStatement(Connection conn) throws SQLException {
				PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); 
				
				ps.setString(1, loginFail.getAccount());
				
				ps.setString(2, loginFail.getIp());
				
				ps.setTimestamp(3, loginFail.getTimestamp());

				return ps;
			}
		}, keyHolder);
		loginFail.setId(keyHolder.getKey().intValue());
	}

	/* (non-Javadoc)
	 * @see org.starsource.forum.server.dao.LoginFailDao#update(org.starsource.forum.server.domain.LoginFail)
	 */
	@Override
	public void update(final LoginFail loginFail) throws DatabaseException {
		final String sql = "UPDATE t_login_fail set account = ?, ip = ?, timestamp = ?  WHERE id = ?";
		jdbcTemplate.update(new PreparedStatementCreator() {
			public PreparedStatement createPreparedStatement(Connection conn) throws SQLException {
				PreparedStatement ps = conn.prepareStatement(sql);
				ps.setString(1, loginFail.getAccount());
				ps.setString(2, loginFail.getIp());
				ps.setTimestamp(3, loginFail.getTimestamp());
				ps.setInt(4, loginFail.getId());
				return ps;
			}
		});
	}

}
